package module

import (
	"leaf/constant"
	"leaf/log"
	"runtime"
	"sync"
)

type Module interface {
	OnPrepare()
	OnInit()
	OnExit()
	Run(closeSignal chan bool)
}

type module struct {
	mi          Module
	closeSignal chan bool
	wg          sync.WaitGroup
}

var modules []*module

func Register(mi Module) {
	m := new(module)
	m.mi = mi
	m.closeSignal = make(chan bool, 1)

	modules = append(modules, m)
}

func Prepare() {
	for i := 0; i < len(modules); i++ {
		modules[i].mi.OnPrepare()
	}
}

func Init() {
	for i := 0; i < len(modules); i++ {
		modules[i].mi.OnInit()
	}

	for i := 0; i < len(modules); i++ {
		m := modules[i]
		m.wg.Add(1)
		go run(m)
	}
}

func Destroy() {
	for i := len(modules) - 1; i >= 0; i-- {
		m := modules[i]
		m.closeSignal <- true
		m.wg.Wait()
		exit(m)
	}
}

func run(m *module) {
	m.mi.Run(m.closeSignal)
	m.wg.Done()
}

func exit(m *module) {
	defer func() {
		if r := recover(); r != nil {
			if constant.LenStackBuf > 0 {
				buf := make([]byte, constant.LenStackBuf)
				l := runtime.Stack(buf, false)
				log.Error("%v: %s", r, buf[:l])
			} else {
				log.Error("%v", r)
			}
		}
	}()

	m.mi.OnExit()
}
